package com.rzgeo.rzmaplib.util;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.shapes.Shape;
import android.support.annotation.NonNull;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

import com.alibaba.fastjson.JSON;
import com.esri.arcgisruntime.concurrent.ListenableFuture;
import com.esri.arcgisruntime.data.Feature;
import com.esri.arcgisruntime.data.FeatureQueryResult;
import com.esri.arcgisruntime.data.FeatureTable;
import com.esri.arcgisruntime.data.Field;
import com.esri.arcgisruntime.data.QueryParameters;
import com.esri.arcgisruntime.data.ShapefileFeatureTable;
import com.esri.arcgisruntime.data.StatisticsQueryParameters;
import com.esri.arcgisruntime.data.StatisticsQueryResult;
import com.esri.arcgisruntime.geometry.Envelope;
import com.esri.arcgisruntime.geometry.Geometry;
import com.esri.arcgisruntime.geometry.GeometryEngine;
import com.esri.arcgisruntime.geometry.Point;
import com.esri.arcgisruntime.geometry.Polygon;
import com.esri.arcgisruntime.geometry.SpatialReference;
import com.esri.arcgisruntime.layers.FeatureLayer;
import com.esri.arcgisruntime.layers.Layer;
import com.esri.arcgisruntime.symbology.Symbol;
import com.rzgeo.rzmaplib.R;
import com.rzgeo.rzmaplib.comp.geoview.IRmlGeoViewHolder;
import com.rzgeo.rzmaplib.model.RmlEnv;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.UUID;

import static android.content.ContentValues.TAG;
import static android.view.accessibility.AccessibilityEvent.INVALID_POSITION;
import static android.widget.AbsListView.CHOICE_MODE_SINGLE;

/**
 * Created by zhanghang on 2018/1/19.
 */

public class RmlUtil
{

    private static String uid;

    public static String getUid() {
        UUID uuid = UUID.randomUUID();

        String uniqueId = uuid.toString();

        return uniqueId.toString();
    }
    public static class Font {

        public static final String ROOT = "fonts/",
                FONTAWESOME = ROOT + "fontawesome-webfont.ttf";
        public static String Default = "DroidSansFallback";

        public static Typeface getTypeface(Context context, String font) {
            return Typeface.createFromAsset(context.getAssets(), font);
        }

    }

    public static class Log {
        private static final String TAG="rml";

        public static void Err(Exception e) {
            if(e!=null){
                e.printStackTrace();
                if(e.getMessage()!=null)
                    android.util.Log.e(TAG,e.getMessage());
            }
        }

        public static void Err(String msg) {
            android.util.Log.e(TAG,msg);
        }

        /***
         * 向开发者输出信息
         * @param msg
         * @return
         */
        public static String Msg(String msg) {
            msg = String.format(">>Wcm:Warn<<,提示： %s\n:", msg);
            android.util.Log.i(TAG, msg);
            return msg;
        }
    }


    public static class Files {
        public static File join(File parent, String name) {
            return new File(parent.getAbsolutePath() + java.io.File.separator + name);
        }

        public static String fileName(File file) {
            int i = file.getName().lastIndexOf(".");
            if(i>-1)
                return file.getName().substring(0,i);
            else
                return file.getName();
        }

        public static String fileExt(File file) {
            int i = file.getName().lastIndexOf(".");
            if(i>-1)
                return file.getName().substring(i);
            else
                return file.getName();
        }

        public static String getFileName(File file) {
            return file.getName().substring(0, file.getName().lastIndexOf("."));
        }

        public static String getPhotoName(String photoFolder) {
            return  photoFolder+ "/IM" + RmlUtil.Convert.toDateString(new Date()) + ".jpg";
        }
    }

    public static class Tip {
        public static String Toast(String msg) {

            Toast.makeText(RmlEnv.getInstance().getActivity().getApplicationContext(),
                    msg, Toast.LENGTH_LONG).show();
            msg = String.format("-=Cgo==Warn=-,提示： %s\n:", msg);
            android.util.Log.i(TAG, msg);
            return msg;
        }

        public static void Alert(Context context,String msg) {
            new AlertDialog
                    .Builder(context, R.style.appalertdialog)
                    .setTitle("注意")
                    .setMessage(msg)
                    .show();
        }
    }

    public final static boolean isValid(String str) {
        return (str != null) && (str.replaceAll("\\s", "").length() > 0);
    }

    public static class SR {
        public static final SpatialReference defaultGeoSR=SpatialReference.create(4326);
        public static final SpatialReference defaultPrjSR=SpatialReference.create(3857);

        public static SpatialReference getGeoSR() {
            return defaultGeoSR;
        }
    }

    public static class Dialog {

        public interface OnInputText {
            void onResult(String content);

            void onCancel();
        }

        public interface OnChoice {
            void onResult(boolean confirm);
        }
        public interface OnChoice2 {
            void onPosi();
            void onNeut();
            void onCancel();
        }

        public interface OnFinish {
            void onFinish();
        }

        public interface OnResult{
            void OnResult(boolean sucess);
        }

        public static void InputString(final Context actvContext, String content, @NonNull final OnInputText onResult) {

            final View editView = LayoutInflater.from(actvContext).inflate(R.layout.comp_text_textinput_small, null);
            final EditText tinEdit = editView.findViewById(R.id.tin_edit);
            tinEdit.setText(content);

            new android.support.v7.app.AlertDialog.Builder(actvContext, R.style.appalertdialog).setTitle("设置文本")
                    .setIcon(android.R.drawable.ic_menu_edit)
                    .setView(editView)
                    .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {

                            String input = tinEdit.getText().toString();
                            if (input.equals("")) {
                                Toast.makeText(actvContext, "输入内容不能为空！" + input, Toast.LENGTH_LONG).show();
                            } else {
                                onResult.onResult(input);
                            }
                        }
                    })
                    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            onResult.onCancel();
                        }
                    })
                    .show();
        }

        public static void EditAttrs(final Context context, RmlData.FeatureLayerData data, @NonNull final OnInputText onResult) {
            RmlEditAttrsHelper.EditAttrs(context,data,onResult);
        }

        public static void InputPassWord(final Context actvContext, String content, final int limit, @NonNull final OnInputText onResult) {

            final View editView = LayoutInflater.from(actvContext).inflate(R.layout.comp_text_textinput_small, null);
            final EditText tinEdit = editView.findViewById(R.id.tin_edit);
            tinEdit.setText(content);

            TextWatcher onChanged = new TextWatcher() {

                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {

                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    if(s!=null&&s.length()>=limit)
                        tinEdit.setBackgroundColor(Color.WHITE);
                    else
                        tinEdit.setBackgroundColor(Color.RED);
                }

                @Override
                public void afterTextChanged(Editable s) {

                }
            };
            tinEdit.addTextChangedListener(onChanged);

            new android.support.v7.app.AlertDialog.Builder(actvContext, R.style.appalertdialog).setTitle("设置文本")
                    .setIcon(android.R.drawable.ic_menu_edit)
                    .setView(editView)
                    .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {

                            String input = tinEdit.getText().toString();
                            if (input.equals("")) {
                                Toast.makeText(actvContext, "输入内容不能为空！" + input, Toast.LENGTH_LONG).show();
                            } else {
                                onResult.onResult(input);
                            }
                        }
                    })
                    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            onResult.onCancel();
                        }
                    })
                    .setCancelable(false)
                    .show();
        }

        public static void Choice(final Context actvContext, String msg, final OnChoice onChoice) {
            new android.support.v7.app.AlertDialog.Builder(actvContext, R.style.appalertdialog).setTitle("搜索")
                    .setIcon(android.R.drawable.ic_menu_edit)
                    .setMessage(msg)
                    .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            if(onChoice!=null)
                                onChoice.onResult(true);
                        }
                    })
                    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            if(onChoice!=null)
                                onChoice.onResult(false);
                        }
                    })
                    .show();
        }

        public static void Choice(final Context actvContext, String msg,String neutTitle,String PosiTitle,@NonNull final OnChoice2 onChoice) {
            new android.support.v7.app.AlertDialog.Builder(actvContext, R.style.appalertdialog).setTitle("搜索")
                    .setIcon(android.R.drawable.ic_menu_edit)
                    .setMessage(msg)
                    .setNeutralButton(neutTitle, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            onChoice.onNeut();
                        }
                    })
                    .setPositiveButton(PosiTitle, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            onChoice.onPosi();
                        }
                    })
                    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            onChoice.onCancel();
                        }
                    })
                    .show();
        }

        public static void ShowMsg(final Context actvContext, String msg,final OnFinish onFinish) {
            new android.support.v7.app.AlertDialog.Builder(actvContext, R.style.appalertdialog).setTitle("搜索")
                    .setIcon(android.R.drawable.ic_menu_edit)
                    .setMessage(msg)
                    .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            if(onFinish!=null)
                                onFinish.onFinish();
                        }
                    })
                    .show();
        }

        public interface OnList {
            void onConfirm(int select);

            void onCancel();

            void onNeutral();
        }




        public static void List(final Context context, String title, ArrayList<String> items, String neutralButtonTitle, int defSelect, final OnList onList) {

            if(items==null)
                return;

            final ListView listView = new ListView(context);

            listView.setMinimumWidth(800);
            listView.setMinimumHeight(600);
            listView.setAdapter(
                    new ArrayAdapter<>(
                            context, android.R.layout.simple_list_item_single_choice, items.toArray(new String[0])));
            listView.setItemsCanFocus(false);
            listView.setChoiceMode(CHOICE_MODE_SINGLE);


            final int[] _lastSelect = {INVALID_POSITION};
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    listView.setItemChecked(position, true);
                    listView.setSelection(position);
                    _lastSelect[0] = position;
                }
            });


            android.support.v7.app.AlertDialog.Builder dlg =
                    new android.support.v7.app.AlertDialog.Builder(context, R.style.appalertdialog)
                            .setIcon(android.R.drawable.ic_menu_edit)
                            .setView(listView)
                            .setTitle(title)
                            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int which) {
                                    if (_lastSelect[0] != INVALID_POSITION) {
                                        onList.onConfirm(_lastSelect[0]);
                                    } else {
                                        Tip.Toast("您必须先选中一个内容");
                                        onList.onCancel();
                                    }
                                }
                            })
                            .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    onList.onCancel();
                                }
                            });

            if(RmlUtil.isValid(neutralButtonTitle)){

                dlg.setNeutralButton(neutralButtonTitle, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        onList.onNeutral();
                    }
                });
            }

            dlg.show();

        }
    }

    public static class Unit{
        public final String name;
        public final double scale;

        public Unit(String name, double scale) {
            this.name = name;
            this.scale = scale;
        }
    }
    
    public static class Const {
        public static Unit[] VolumeUtils=new Unit[]{
                new Unit("方",1),
                new Unit("万方",10000),
                new Unit("亿方",100000000),
                new Unit("立方千米",1000*1000*1000)
        };

        public static Unit[] AreaUtils=new Unit[]{
                new Unit("平方米",1),
                new Unit("亩",2000/3),
                new Unit("公顷",10000),
                new Unit("平方千米",1000*1000)
        };
    }

    /**
     * Created by zhanghang on 2018/1/19.
     */

    public interface OnFail{
        void OnFail(String msg);
    }

    public static class Convert {
        public static final String map2JsonStr(Map map){
            return JSON.toJSONString(map);


        }

        public static final Map jsonToMap(String json){
            return JSON.parseObject(json, Map.class);
        }

        public static float Float(Object var) {
            if (var != null) {
                if (var instanceof Long)
                    return ((Long) var).floatValue();
                if (var instanceof Integer)
                    return ((Integer) var).floatValue();
                if (var instanceof Float)
                    return ((Float) var).floatValue();
                if (var instanceof Double)
                    return ((Double) var).floatValue();
                if (var instanceof String)
                    return Float.valueOf(((String) var));
                else
                    return 0.0f;
            } else
                return 0;
        }

        private static final SimpleDateFormat __formatter = new SimpleDateFormat("yyyyMMddHHmmss");

        public static String toStringFromDate(Date date) {
            return __formatter.format(date);
        }

        public static String toString(Object obj) {
            if(obj==null)
                return "";
            else if(obj instanceof String)
                return (String) obj;
            else
                return obj.toString();
        }

        public static String toDateString(Object date) {
            if(date==null)
                return "";
            else if(date instanceof Date)
                return __formatter.format(date);
            else
                return date.toString();
        }

        public static String inputStream2String(InputStream in) throws IOException {
            StringBuffer out = new StringBuffer();
            byte[] b = new byte[4096];
            for (int n; (n = in.read(b)) != -1; ) {
                out.append(new String(b, 0, n));
            }
            return out.toString();
        }

        public static long toLong(Object o) {
            if(o==null)
                return 0;
            if(o instanceof Long)
                return (Long) o;
            if(o instanceof String)
                return Long.valueOf(o.toString());
            return 0;
        }

        public static int Int(Object o) {
            if(o==null)
                return 0;
            if(o instanceof Integer)
                return (Integer) o;
            if(o instanceof String)
                return Integer.valueOf(o.toString());
            else
                return Integer.valueOf(o.toString());
        }
    }

    public static class Copy {
        public static Symbol copy(Symbol symbol) {
            return Symbol.fromJson(symbol.toJson());
        }
    }

    public static class Dict {
        public static String getString(Map<String, Object> a, String key) {
            if(a==null)
                return null;
            if(key==null)
                return null;
            Object o = a.get(key);
            if(o==null)
                return null;
            else if(o instanceof String)
                return (String) o;
            else
                return o.toString();
        }

        public static int getInt(Map<String, Object> a, String key) {
            Object o = a.get(key);
            if(o==null)
                return 0;
            else if(o instanceof Long)
                return ((Long) o).intValue();
            else if(o instanceof Integer)
                return ((Integer) o);
            else
                return Integer.valueOf(o.toString());
        }
    }

    public static class Geo {
        public static Geometry fitZValue(Geometry geo, boolean targetHasZ) {
            if(geo.hasZ()&&(!targetHasZ)){
                if(geo instanceof Point){
                    Point pon=(Point) geo;
                    geo=new Point(pon.getX(),pon.getY(),pon.getSpatialReference());
                }
            }
            return geo;
        }

        public static Point getLabelPoint(Geometry g) {
            switch (g.getGeometryType()){
                case ENVELOPE:
                    return ((Envelope)g).getCenter();
                case POINT:
                    return (Point)g;
                case POLYGON:
                    return GeometryEngine.labelPoint((Polygon) g);
                case MULTIPOINT:
                    Point ct = g.getExtent().getCenter();
                    GeometryEngine.nearestVertex(g,ct);
                case POLYLINE:
                    Point ct2 = g.getExtent().getCenter();
                    GeometryEngine.nearestVertex(g,ct2);
                    default:
                        return null;
            }
        }

        public static IRmlGeoViewHolder.ILocMgr.Info calculateLocInfo(Queue<IRmlGeoViewHolder.ILocMgr.Info> result, Date date) {
            if(result.size()==0){
                return null;
            }else if(result.size()==1){
                return result.element();
            }else{
                IRmlGeoViewHolder.ILocMgr.Info last=result.remove();
                for (int i = 0; i <result.size()-1 ; i++) {
                    IRmlGeoViewHolder.ILocMgr.Info next = result.remove();
                    if(next.date.getTime()-date.getTime()>last.date.getTime()-date.getTime())
                        return last;
                    else
                        last=next;
                }
                return last;
            }
        }
    }

    public static class Features
    {
        public static ArrayList<Feature> getQueryResult(ListenableFuture<FeatureQueryResult> qr) {
            try {
                ArrayList<Feature> fs=new ArrayList<>();
                FeatureQueryResult r = qr.get();
                Iterator<Feature> it = r.iterator();
                while (it.hasNext()){
                    fs.add(it.next());
                }
                return fs;
            } catch (Exception e) {
                Log.Err(e);
            }
            return null;
        }


        public static void queryAndDelete(final FeatureTable featureTable, QueryParameters qp, final OnDelResult onResult) {
            final ListenableFuture<FeatureQueryResult> qf = featureTable.queryFeaturesAsync(qp);
            qf.addDoneListener(new Runnable() {
                @Override
                public void run() {
                    final ArrayList<Feature> fs = getQueryResult(qf);
                    if(fs==null)
                        onResult.onFail();

                    final ArrayList<Feature> f2del = new ArrayList<>(fs.size());
                    for (Feature f:fs
                         ) {
                        if(featureTable.canDelete(f)){
                            f2del.add(f);
                        }else{
                            Log.Err("发现无法删除的数据");
                        }
                    }
                    final ListenableFuture<Void> df = featureTable.deleteFeaturesAsync(f2del);
                    df.addDoneListener(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                df.get();
                                onResult.onResult(f2del.size(),fs.size()-f2del.size());
                            } catch (Exception e) {
                                Log.Err(e);
                                onResult.onFail();
                            }
                        }
                    });
                }
            });
        }

        public interface OnDelResult {
            void onResult(int numDel,int numDelFail);
            void onFail();
        }

        public interface OnResult{
            void onResult();
            void onFail();
        }
        public static Field getFIDField(List<Field> fields) {
            for (Field f:fields) {
                if(f.getFieldType()== Field.Type.OID){
                    return f;
                }
            }
            return null;
        }

        public static void replaceFeature(final FeatureTable ft, ArrayList<Feature> features2Add, final ArrayList<Feature> features2Del, final OnResult onResult) {

            final ListenableFuture<Void> dr = ft.addFeaturesAsync(features2Add);
            dr.addDoneListener(new Runnable() {
                @Override
                public void run() {
                    try {
                        dr.get();

                        final ListenableFuture<Void> dr = ft.deleteFeaturesAsync(features2Del);
                        dr.addDoneListener(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    dr.get();
                                    onResult.onResult();
                                } catch (Exception e) {
                                    RmlUtil.Tip.Toast("无法删除");
                                    onResult.onFail();
                                }
                            }
                        });
                    } catch (Exception e) {
                        RmlUtil.Tip.Toast("无法添加新要素");
                        onResult.onFail();
                    }
                }
            });
        }
    }

    public interface LoadaebResult
    {
        void onFinish(Loader.LoadaebleItem loadaebleItem);

        void onFail(Loader.LoadaebleItem loadaebleItem, String msg);
    }

    public static class Loader implements LoadaebResult {

        public static void load(LoadaebleItem[] refs,OnResult result){
            new Loader(refs,result);
        }

        public static class Query implements LoadaebleItem{

            public final FeatureTable _table;
            public final QueryParameters _qp;
            public final queryResult _result;
            public StatisticsQueryParameters _sqp;

            public static abstract class queryResult{
                Exception e;
            }
            public static class QueryExtentResult extends queryResult{
                public Envelope envelope;
            }
            public static class QueryFeatureResult extends queryResult{

                public List<Field> fields;
                public ArrayList<Feature> features;
            }
            public static class QueryCountResult extends queryResult{

                public Long count;
            }
            public static class QueryStaticsResult extends queryResult{

                public StatisticsQueryResult statistic;
            }

            public Query(FeatureTable table, QueryParameters qp ,queryResult result) {
                _table=table;
                _qp=qp;
                _result=result;
                _sqp=null;
            }

            public Query(FeatureTable table, StatisticsQueryParameters sqp ,queryResult result) {
                _table=table;
                _qp=null;
                _result=result;
                _sqp=sqp;

            }
            @Override
            public void load(final LoadaebResult result) {
                if(_result instanceof QueryExtentResult){
                    final ListenableFuture<Envelope> qt1 = _table.queryExtentAsync(_qp);
                    qt1.addDoneListener(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Envelope envelope=qt1.get();
                                ((QueryExtentResult)_result).envelope=envelope;
                                result.onFinish(Query.this);
                            } catch (Exception e) {
                                _result.e=e;
                                result.onFail(Query.this,"失败");
                            }

                        }
                    });
                }
                else if(_result instanceof QueryCountResult){
                    final ListenableFuture<Long> qt2 = _table.queryFeatureCountAsync(_qp);
                    qt2.addDoneListener(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Long count = qt2.get();
                                ((QueryCountResult)_result).count=count;
                                result.onFinish(Query.this);
                            } catch (Exception e) {
                                _result.e=e;
                                result.onFail(Query.this,"失败");
                            }
                        }
                    });
                }
                else if(_result instanceof QueryFeatureResult){
                    final ListenableFuture<FeatureQueryResult> qt2 = _table.queryFeaturesAsync(_qp);
                    qt2.addDoneListener(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                FeatureQueryResult features = qt2.get();
                                Iterator<Feature> iterator = features.iterator();
                                ArrayList<Feature> featureLsit=new ArrayList<>();

                                while (iterator.hasNext()) {
                                    featureLsit.add(iterator.next());
                                }

                                ((QueryFeatureResult)_result).features=featureLsit;
                                ((QueryFeatureResult)_result).fields=_table.getFields();
                                result.onFinish(Query.this);
                            } catch (Exception e) {
                                _result.e=e;
                                result.onFail(Query.this,"失败");
                            }

                        }
                    });
                }
                else if(_result instanceof QueryStaticsResult){
                    final ListenableFuture<StatisticsQueryResult> qt2 = _table.queryStatisticsAsync(_sqp);
                    qt2.addDoneListener(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                StatisticsQueryResult statistic = qt2.get();
                                ((QueryStaticsResult)_result).statistic=statistic;
                                result.onFinish(Query.this);
                            } catch (Exception e) {
                                _result.e=e;
                                result.onFail(Query.this,"失败");
                            }

                        }
                    });
                }
            }
        }

        private final OnResult _result;
        private final LoadaebleItem[] _refs;
        private Map<LoadaebleItem,LoadResult>_refs2LoadResult;

        public interface OnResult {
            void onFinish(Map<LoadaebleItem,LoadResult>refs2LoadResult);
        }

        private Loader(@NonNull LoadaebleItem[] refs,@NonNull OnResult result) {
            _refs2LoadResult=new HashMap<>(refs.length);

            if(refs.length==0)
                result.onFinish(_refs2LoadResult);

            _refs=refs;
            _result=result;

            for (LoadaebleItem ref:_refs) {
                ref.load(this);
            }
        }


        @Override
        public void onFinish(LoadaebleItem loadaebleItem) {
            _refs2LoadResult.put(loadaebleItem,new LoadResult(true,null));
            check();
        }

        @Override
        public void onFail(LoadaebleItem loadaebleItem, String msg) {
            _refs2LoadResult.put(loadaebleItem,new LoadResult(false,msg));
            check();
        }


        private void check() {
            if(_refs2LoadResult.size()==_refs.length){
                _result.onFinish(_refs2LoadResult);
            }
        }

        public interface LoadaebleItem{
            public void load(LoadaebResult result);
        }

        public static class LoadResult{
            public boolean valid;
            public boolean loaded;
            public String msg;

            public LoadResult(boolean valid, String msg) {
                this.loaded=true;
                this.valid = valid;
                this.msg = msg;
            }
        }
    }

    public static class Asset {

        public static String getFile(Context context, String filePath) {
            try {
                InputStreamReader inputReader = new InputStreamReader(
                        context.getResources().getAssets().open(filePath) );
                BufferedReader bufReader = new BufferedReader(inputReader);
                String line="";
                String Result="";
                while((line = bufReader.readLine()) != null)
                    Result += line;
                return Result;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return filePath;
        }
    }

    public static class Layers {
        public static String getName(Layer l) {
            if(l instanceof FeatureLayer){
                if(((FeatureLayer) l).getFeatureTable() instanceof ShapefileFeatureTable){
                    File f=new File(
                            ((ShapefileFeatureTable)((FeatureLayer) l).getFeatureTable()).getPath()
                    );
                    return f.getName();
                }else
                    return l.getName();
            }
            return l.getName();

        }
    }
}
